#pragma once

#include "../common/dispatcher.hpp"
#include "rpc_registry.hpp"
#include "rpc_router.hpp"
#include "../client/rpc_client.hpp"
#include "rpc_topic.hpp"

namespace JsonMuduoRPC
{
    namespace server
    {
        // 服务注册中心服务器，针对服务注册与发现的请求做处理
        class RegistryServer
        {
        public:
            using ptr = std::shared_ptr<RegistryServer>;

            RegistryServer(const uint16_t port)
                : _dispatcher(std::make_shared<Dispatcher>()),
                  _p_d_manager(std::make_shared<ProviderDiscoverManager>())
            {
                auto service_req_cb = std::bind(&ProviderDiscoverManager::onServiceRequest, _p_d_manager.get(),
                                                std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerHandler<ServiceRequest>(MType::REQ_SERVICE, service_req_cb);

                _server = ServerFactory::create(port);

                _server->setMessageCallBack(std::bind(&Dispatcher::onMessage, _dispatcher.get(),
                                                      std::placeholders::_1, std::placeholders::_2));
                _server->setCloseCallBack(std::bind(&RegistryServer::onConnShutdown, this,
                                                    std::placeholders::_1));
            }

            void start()
            {
                _server->start();
            }

        private:
            void onConnShutdown(const BaseConnection::ptr &conn)
            {
                _p_d_manager->onConnectionShutdown(conn);
            }

        private:
            BaseServer::ptr _server;
            Dispatcher::ptr _dispatcher;
            ProviderDiscoverManager::ptr _p_d_manager;
        };

        // RPC调用服务器，可以选择开启服务注册功能以实现服务注册
        class RPCServer
        {
        public:
            using ptr = std::shared_ptr<RPCServer>;

            RPCServer(const Address &access_addr,
                      bool enableRegistry = false, const Address &registry_server_addr = Address())
                : _access_addr(access_addr),
                  _dispatcher(std::make_shared<Dispatcher>()),
                  _rpc_router(std::make_shared<RPCRouter>())
            {
                if (enableRegistry)
                {
                    _enableRegistry = enableRegistry;
                    _registry_client = std::make_shared<client::RegistryClient>(
                        registry_server_addr.first, registry_server_addr.second);
                }

                auto rpc_req_cb = std::bind(&RPCRouter::onRpcRequest, _rpc_router.get(),
                                            std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerHandler<RPCRequest>(MType::REQ_RPC, rpc_req_cb);

                _server = ServerFactory::create(access_addr.second);

                _server->setMessageCallBack(std::bind(&Dispatcher::onMessage, _dispatcher.get(),
                                                      std::placeholders::_1, std::placeholders::_2));
            }

            void registryMethod(const ServiceDescribe::ptr &service_disc)
            {
                _rpc_router->registerService(service_disc);
                if (_enableRegistry)
                    _registry_client->registryRequest(service_disc->getServiceName(), _access_addr);
            }

            void start()
            {
                _server->start();
            }

        private:
            bool _enableRegistry;
            Address _access_addr;
            BaseServer::ptr _server;
            Dispatcher::ptr _dispatcher;
            RPCRouter::ptr _rpc_router;
            client::RegistryClient::ptr _registry_client;
        };

        class TopicServer
        {
        public:
            using ptr = std::shared_ptr<TopicServer>;

            TopicServer(const uint16_t port)
                : _dispatcher(std::make_shared<Dispatcher>()),
                  _topic_manager(std::make_shared<TopicManager>())
            {
                auto topic_req_cb = std::bind(&TopicManager::onTopicRequest, _topic_manager.get(),
                                              std::placeholders::_1, std::placeholders::_2);
                _dispatcher->registerHandler<TopicRequest>(MType::REQ_TOPIC, topic_req_cb);

                _server = ServerFactory::create(port);

                _server->setMessageCallBack(std::bind(&Dispatcher::onMessage, _dispatcher.get(),
                                                      std::placeholders::_1, std::placeholders::_2));
                _server->setCloseCallBack(std::bind(&TopicServer::onConnShutdown, this,
                                                    std::placeholders::_1));
            }

            void start()
            {
                _server->start();
            }

        private:
            void onConnShutdown(const BaseConnection::ptr &conn)
            {
                _topic_manager->onShutdown(conn);
            }

        private:
            BaseServer::ptr _server;
            Dispatcher::ptr _dispatcher;
            TopicManager::ptr _topic_manager;
        };
    }
}